#include "synchronousav.h"
#include "libavinclude.h"
#include "mediaimagehandler.h"
#include "timersynchabstract.h"
#include "Task_Base/CriticalSection.h"
#define AV_SYNC_THRESHOLD   0.01
#define AV_NOSYNC_THRESHOLD 10.0
SynchronousAV::SynchronousAV()
{
    show_image_handler  = 0;
    m_oSynchtarget      = 0;
    frame_last_duration = 40e-3;
    frame_last_pts      = 0;
    frame_timer         = 0;
}

SynchronousAV::~SynchronousAV()
{

}

void SynchronousAV::init(MediaImagehandler *handler, TimerSynchAbstract *target)
{
    show_image_handler  = handler;

    m_oSynchtarget      = target;

    frame_timer         = (double)av_gettime() / 1000000.0;

    frame_last_duration = 40e-3;

    frame_last_pts      = 0;
}

bool SynchronousAV::syn_image_handler(unsigned char *data, int size, double pts,int width, int height)//rgb 数据
{
    std::string str_buf;
    str_buf.append((char*)&pts,sizeof(double));  
    str_buf.append((char*)&width,sizeof(int)); 
    str_buf.append((char*)&height,sizeof(int));
    str_buf.append((char*)&size,sizeof(int));  
    str_buf.append((char*)data,size);	
    putq(str_buf);
    return true;
}

int SynchronousAV::close()
{
    std::string str("");

    m_oSynchtarget = 0;

    int nthread  =thr_count();

    for (int i =0 ;i<nthread ;i++)
        putq(str);

    wait();
    return true;
}

int SynchronousAV::svc()
{
    std::string str ="";

    while(getq(str))	
    {
        if (str=="")	//为空为退出标志 0字节 情况
        {
	    if(show_image_handler)
	       show_image_handler->media_image_handler(0,0,0,0,0);
            return true;
        }

        const char *pbuf		= str.data();
        int			buf_len		= str.size();

        double  pts     = *((double *)pbuf);
        int     width   = *((int *)(pbuf + sizeof(pts)));
        int     height  = *((int *)(pbuf + sizeof(pts) + sizeof(width)));
        int     size    = *((int *)(pbuf + sizeof(pts) + sizeof(width) + sizeof(height)));

        if(size + sizeof(pts) + sizeof(width) + sizeof(height) + sizeof(size) == buf_len)
        {
            const char *v_data  =   pbuf + sizeof(double) + sizeof(int) + sizeof(int) + sizeof(int);

            char *data = const_cast<char *>(v_data);

            int ret = 0;

            while((ret = syn_image_audio((unsigned char *)data,size,pts,width,height)) == 1)
            {
                av_usleep(20*1000);//40ms
            }
            if(ret == 0)
                av_usleep(20*1000);//40ms
        }else
        {
            int A  =0;
        }
    }
    return true;
}

int SynchronousAV::syn_image_audio(unsigned char *data, int size, double pts, int width, int height)
{
    double last_duration,delay, sync_threshold, ref_clock, diff;

    last_duration = pts - frame_last_pts;
    if (last_duration > 0 && last_duration < 10.0)
    {
       frame_last_duration = last_duration;
    }

    delay = frame_last_duration;

    if(m_oSynchtarget == 0)
       return -1;

    ref_clock = m_oSynchtarget->time_stamp();//获取音频时间戳
    diff = pts - ref_clock;			//算出这张图pts 与当前音频 的时刻配不配 差距过大 就丢弃

    sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD;//算出 延迟

    if (fabs(diff) < AV_NOSYNC_THRESHOLD)	//差距小于10秒
    {
       if (diff <= -sync_threshold)// 如果  diff 小于0  说明  音频播放太快
       {
           delay = 0;
       }
       else if (diff >= sync_threshold)//说明  视频频播放太快
       {
           delay = 2 * delay;
       }
    }

    timer = (av_gettime() / 1000000.0);

    if (timer <  (frame_timer + delay))
    {
       //视频时间轴 跑过 系统时间轴
       return 1;//表示等20ms后 再次传递本帧一次
    }

    if(delay > 0)
    {
       double calculate = delay * FFMAX(1, floor((timer - frame_timer) / delay));
       frame_timer += calculate;
    }

    frame_last_pts =  pts;      //保存这一次播放的视频时刻
    //frame_last_pts =  pts;      //保存这一次播放的视频时刻
    //拉取下一张图 判断 是否进入下一帧模式
    //..................................
    std::string strNext ="";
    if(frontq(strNext))
    {
       const char *next_buf		= strNext.data();
       double      next_pts        = *((double *)next_buf);

      double duration = next_pts - pts;
      if(timer > (frame_timer + duration))
      {
         // qDebug(QString::fromUtf8("-----------...").toLocal8Bit().data());
           return -1;//表示不暂停 立马拉取队列下一帧
      }
    }
    if(show_image_handler)
       show_image_handler->media_image_handler(data,size,width,height,ref_clock);

    return 0;//正常等待20ms后拉取下一帧
}
